/* @(#)FseDocumentView.java
** 
** Copyright (C) 2012 by Steven D. Stamps
**
**             Trademarks & Copyrights
** Flywheel Management Science(TM), Flywheel Management Model(TM),
** Flywheel Story Editor(TM) and FlywheelMS(TM) are exclusive trademarks
** of Steven D. Stamps and may only be used freely for the purpose of
** identifying the unforked version of this software.  Subsequent forks
** may not use these trademarks.  All other rights are reserved.
**
** DecKanGL (Decorated Kanban Glyph Language) and TribKn (Tribal Knowledge)
** are also exclusive trademarks of Steven D. Stamps.  These may be used
** freely within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** gConGUI (game Controller Graphical User Interface) is an exclusive
** trademark of Steven D. Stamps.  This trademark may be used freely
** within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** Trademark information is available at
** <http://www.flywheelms.com/trademarks>
**
** Flywheel Management Science(TM) is a copyrighted body of management
** metaphors, governance processes, and leadership techniques that is
** owned by Steven D. Stamps.  These copyrighted materials may be freely
** used, without alteration, by the community (users and developers)
** surrounding this GPL3-licensed software.  Additional copyright
** information is available at <http://www.flywheelms.org/copyrights>
**
**              GPL3 Software License
** This program is free software: you can use it, redistribute it and/or
** modify it under the terms of the GNU General Public License, version 3,
** as published by the Free Software Foundation. This program is distributed
** in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE.  See the GNU General Public License for more details. You should
** have received a copy of the GNU General Public License, in a file named
** COPYING, along with this program.  If you cannot find your copy, see
** <http://www.gnu.org/licenses/gpl-3.0.html>.
*/

package com.flywheelms.library.fse.views;

import java.util.Date;

import org.json.JSONObject;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.widget.FrameLayout;

import com.flywheelms.library.R;
import com.flywheelms.library.fca.FlywheelCommunityAuthentication;
import com.flywheelms.library.fmm.enumerator.FmmLockStatus;
import com.flywheelms.library.fmm.node.NodeId;
import com.flywheelms.library.fmm.node.impl.nodefrag.NodeFragAuditBlock;
import com.flywheelms.library.fmm.node.interfaces.horizontal.FmmNodeAudit;
import com.flywheelms.library.fmm.serialization.FmmSerialization;
import com.flywheelms.library.fse.FseDocumentSectionType;
import com.flywheelms.library.fse.enumerator.FseContentModificationState;
import com.flywheelms.library.fse.fragment.FlywheelStoryEditorFragment;
import com.flywheelms.library.fse.model.FseDocument;
import com.flywheelms.library.fse.model.FseDocumentSectionParagraphAudit;
import com.flywheelms.library.fse.model.FseDocumentTransactionType;
import com.flywheelms.library.gcg.helper.GcgHelper;
import com.flywheelms.library.gcg.interfaces.GcgFlingController;

public class FseDocumentView extends FrameLayout implements FmmSerialization, FmmNodeAudit, GcgFlingController {

	private FlywheelStoryEditorFragment fseFragment;
	private FrameLayout documentViewLayout;
	private FseDocument baselineDocument;
	private String documentId;
	private String parentNodeIdString;
	private boolean forPublication = false;
	private int documentMarginLeft;
	private FseDocumentSectionType initialDocumentSectionType;
	private FseDocumentSectionType activeDocumentSectionType;
	private FseDocumentSectionTribKnView tribKnSectionView;
	private FseDocumentSectionAuditView auditSectionView;
	private FseDocumentSectionHistoryView historySectionView;
	private FseDocumentSectionStoryView storySectionView;
	private FseDocumentSectionNotesView notesSectionView;
	private float previousMotionEventX;
	private float previousMotionEventY;
	private boolean initializationPhase = true;

	public FseDocumentView(Context aContext, AttributeSet anAttributeSet) {
		super(aContext, anAttributeSet);
		this.documentViewLayout = (FrameLayout) LayoutInflater.from(aContext).inflate(
				R.layout.fse__document_view, this);
		this.tribKnSectionView = new FseDocumentSectionTribKnView(aContext, anAttributeSet);
		this.auditSectionView = new FseDocumentSectionAuditView(aContext, anAttributeSet);
		this.historySectionView = new FseDocumentSectionHistoryView(aContext, anAttributeSet);
		this.storySectionView = new FseDocumentSectionStoryView(aContext, anAttributeSet);
		this.notesSectionView = new FseDocumentSectionNotesView(aContext, anAttributeSet);
		setOnTouchListener(
				GcgHelper.getInstance().getFlingTouchListener(aContext, this));
	}
	
	public void initialize(FlywheelStoryEditorFragment anFseFragment) {
		this.fseFragment = anFseFragment;
		this.tribKnSectionView.initialize(this);
		this.auditSectionView.initialize(this);
		this.historySectionView.initialize(this);
		this.storySectionView.initialize(this);
		this.notesSectionView.initialize(this);
	}

    @Override
    public boolean onInterceptTouchEvent(MotionEvent aMotionEvent) {
    	if(GcgHelper.isHorizontalFlingEvent(aMotionEvent, this)) {
    		return true;
    	}
        return super.onInterceptTouchEvent(aMotionEvent);
    }
	
	public void viewDocument(FseDocument anFseDocument) {
		viewDocument(anFseDocument, anFseDocument);
	}
	
	public void viewDocument(FseDocument anFseDocument, FseDocument aDocumentBaseline) {
		FseDocument theDocumentClone = anFseDocument.clone();
		this.baselineDocument = aDocumentBaseline;
		this.documentId = theDocumentClone.getDocumentId();
		this.parentNodeIdString = theDocumentClone.getParentNodeIdString();
		this.forPublication = theDocumentClone.forPublication();
		this.documentMarginLeft = theDocumentClone.getDocumentMarginLeft();
		this.initialDocumentSectionType = this.activeDocumentSectionType = theDocumentClone.getInitialDocumentSectionType();
		if(this.forPublication) {
			this.tribKnSectionView.viewDocumentSection(theDocumentClone.getDocumentSectionTribKn());
		}
		this.auditSectionView.viewDocumentSection(theDocumentClone.getDocumentSectionAudit());
		this.historySectionView.viewDocumentSection(theDocumentClone.getDocumentSectionHistory());
		this.storySectionView.viewDocumentSection(theDocumentClone.getDocumentSectionStory());
		this.notesSectionView.viewDocumentSection(theDocumentClone.getDocumentSectionNotes());
		activateDocumentSectionTab(this.activeDocumentSectionType);
	}
	
	public void revertDocument() {
		GcgHelper.makeToast("Reverting document...");
		viewDocument(this.baselineDocument);
		resetModificationState();
	}
	
	public FrameLayout getDocumentViewLayout() {
		return this.documentViewLayout;
	}
	
	public FseDocumentSectionType getActiveDocumentSectionType() {
		return this.activeDocumentSectionType;
	}
	
	public FseDocumentSectionViewLegacy getActiveDocumentSectionView() {
		switch (this.activeDocumentSectionType) {
		case TRIBKN:
			return this.tribKnSectionView;
		case AUDIT:
			return this.auditSectionView;
		case HISTORY:
			return this.historySectionView;
		case NOTES:
			return this.notesSectionView;
		case STORY:
			return this.storySectionView;
		default:
			return null;
		}
	}

	public void setActiveDocumentSection(FseDocumentSectionType activeDocumentSection) {
		this.activeDocumentSectionType = activeDocumentSection;
	}

	public FseDocumentSectionTribKnView getTribKnSectionView() {
		return this.tribKnSectionView;
	}

	public FseDocumentSectionAuditView getAuditSectionView() {
		return this.auditSectionView;
	}

	public FseDocumentSectionHistoryView getHistorySectionView() {
		return this.historySectionView;
	}

	public FseDocumentSectionParagraphEditorContentViewLegacy getStorySectionView() {
		return this.storySectionView;
	}

	public FseDocumentSectionParagraphEditorContentViewLegacy getNotesSectionView() {
		return this.notesSectionView;
	}

	public FseDocument getBaselineDocument() {
		return this.baselineDocument;
	}
	
	public String getDocumentId() {
		return this.documentId;
	}
	
	public String getParentNodeIdString() {
		return this.parentNodeIdString;
	}
	
	public FlywheelStoryEditorFragment getFseFragment() {
		return this.fseFragment;
	}

	public boolean documentIsModified() {
		if(this.storySectionView.isContentModified() || this.notesSectionView.isContentModified()) {
			return true;
		}
		String theSerializedFseDocumentViewForComparison = getSerializedForComparisonToBaseline();  // because we don't care about certain changes to state
		if(! theSerializedFseDocumentViewForComparison.equals(this.baselineDocument.getSerializedForComparison())) {
			return true;
		}
		return false;
	}

	public int getDocumentMarginLeft() {
		return this.baselineDocument.getDocumentMarginLeft();
	}

	public FseDocumentSectionParagraphEditorContentViewLegacy getActiveParagraphEditorView() {
		switch (this.activeDocumentSectionType) {
		case STORY:
			return getStorySectionView();
		case NOTES:
			return getNotesSectionView();
		default:
			return null;
		}
	}

	public String getSerializedForComparisonToBaseline() {
		JSONObject theJsonObject = generateFseDocumentForComparison().getJsonObject();
		return theJsonObject.toString();
	}

	@Override
	public String getSerialized() {
		return getJsonObject().toString();
	}

	@Override
	public JSONObject getJsonObject() {
		return generateFseDocument().getJsonObject();
	}

	/**
	 * done here instead of FseDocument, in order to keep the "model" decoupled from the view 
	 */
	private FseDocument generateFseDocument() {
		FseDocument theDocument = new FseDocument(this.documentId, this.parentNodeIdString, this.documentMarginLeft);
		theDocument.setForPublication(this.forPublication);
		theDocument.setInitialDocumentSectionType(this.activeDocumentSectionType);
		if(this.forPublication) {
			theDocument.setDocumentSectionTribKn(this.tribKnSectionView);
		}
		theDocument.setDocumentSectionAudit(this.auditSectionView);
		theDocument.setDocumentSectionHistory(this.historySectionView);
		theDocument.setDocumentSectionStory(this.storySectionView);
		theDocument.setDocumentSectionNotes(this.notesSectionView);
		return theDocument;
	}
	
	private FseDocument generateFseDocumentForComparison() {
		FseDocument theDocument = generateFseDocument();
		theDocument.setInitialDocumentSectionType(this.initialDocumentSectionType);
		theDocument.getDocumentSectionNotes().setInitialParagraphFocusIndex(this.notesSectionView.getOriginalInitialParagraphFocusIndex());
		theDocument.getDocumentSectionNotes().setInitialParagraphFocusCursorPosition(this.notesSectionView.getOriginalInitialParagraphFocusCursorPosition());
		theDocument.getDocumentSectionStory().setInitialParagraphFocusIndex(this.notesSectionView.getOriginalInitialParagraphFocusIndex());
		theDocument.getDocumentSectionStory().setInitialParagraphFocusCursorPosition(this.notesSectionView.getOriginalInitialParagraphFocusCursorPosition());
		return theDocument;
	}
	
	public void setDocumentBaseline(JSONObject aJsonObject) {
		this.baselineDocument = new FseDocument(aJsonObject.toString());
	}

	public void activateDocumentSectionTab(FseDocumentSectionType aDocumentSectionType) {
		if(this.initializationPhase) {
			this.initializationPhase = false;
		} else {
			this.getActiveDocumentSectionView().deactivateDocumentSectionTab();
		}
		this.activeDocumentSectionType = aDocumentSectionType;
		switch(aDocumentSectionType) {
			case TRIBKN:
				this.tribKnSectionView.activateDocumentSectionTab();
				break;
			case AUDIT:
				this.auditSectionView.activateDocumentSectionTab();
				break;
			case HISTORY:
				this.historySectionView.activateDocumentSectionTab();
				break;
			case NOTES:
				this.notesSectionView.activateDocumentSectionTab();
				break;
			case STORY:
				this.storySectionView.activateDocumentSectionTab();
				break;
			default:
		}
	}

	////  START Audit Block  Wrapper ////

	@Override
	public NodeFragAuditBlock getAuditBlock() {
		return this.auditSectionView.getDocumentSectionAudit().getAuditBlock();
	}

	@Override
	public void setAuditBlock(NodeFragAuditBlock anAuditBlock) {
		this.auditSectionView.getDocumentSectionAudit().setAuditBlock(anAuditBlock);
	}

	//Created  //

	@Override
	public NodeId getCreatedBy() {
		return getAuditBlock().getCreatedBy();
	}

	@Override
	public String getCreatedByNodeIdString() {
		return getAuditBlock().getCreatedBy().getNodeIdString();
	}

	@Override
	public void setCreatedBy(NodeId aNodeId) {
		getAuditBlock().setCreatedBy(aNodeId);
	}

	@Override
	public void setCreatedBy(String aNodeIdString) {
		getAuditBlock().setCreatedBy(aNodeIdString);
	}

	@Override
	public Date getCreatedTimestamp() {
		return getAuditBlock().getCreatedTimestamp();
	}

	@Override
	public void setCreatedTimestamp(Date aCreatedTimestamp) {
		getAuditBlock().setCreatedTimestamp(aCreatedTimestamp);
	}

	//Updated  //

	@Override
	public NodeId getLastUpdatedBy() {
		return getAuditBlock().getLastUpdatedBy();
	}

	@Override
	public String getLastUpdatedByNodeIdString() {
		return getAuditBlock().getLastUpdatedBy().getNodeIdString();
	}

	@Override
	public void setLastUpdatedBy(NodeId aNodeId) {
		getAuditBlock().setLastUpdatedBy(aNodeId);
	}

	@Override
	public void setLastUpdatedBy(String aNodeIdString) {
		getAuditBlock().setLastUpdatedBy(aNodeIdString);
	}

	@Override
	public Date getLastUpdatedTimestamp() {
		return getAuditBlock().getLastUpdatedTimestamp();
	}

	@Override
	public void setLastUpdatedTimestamp(Date aLastUpdate) {
		getAuditBlock().setLastUpdatedTimestamp(aLastUpdate);
	}

	//Locked  //

	@Override
	public NodeId getLockedBy() {
		return getAuditBlock().getLockedBy();
	}

	@Override
	public String getLockedByNodeIdString() {
		return getAuditBlock().getLockedBy().getNodeIdString();
	}

	@Override
	public void setLockedBy(NodeId aNodeId) {
		getAuditBlock().setLockedBy(aNodeId);
	}

	@Override
	public void setLockedBy(String aNodeIdString) {
		getAuditBlock().setLockedBy(aNodeIdString);
	}

	@Override
	public Date getLockedTimestamp() {
		return getAuditBlock().getLockedTimestamp();
	}

	@Override
	public void setLockedTimestamp(Date aLockedTimestamp) {
		getAuditBlock().setLockedTimestamp(aLockedTimestamp);
	}

	@Override
	public void lock() {
		getAuditBlock().setLockedBy(FlywheelCommunityAuthentication.getInstance().getFcaUserCredentials().getFcaUserId());
		getAuditBlock().setLockedTimestamp(new Date());
		getAuditBlock().setLocked(true);
	}

	@Override
	public void unlock() {
		// we want to know who unlocked it, and when
		getAuditBlock().setLockedBy(FlywheelCommunityAuthentication.getInstance().getFcaUserCredentials().getFcaUserId());
		getAuditBlock().setLockedTimestamp(new Date());
		getAuditBlock().setLocked(false);
	}

	@Override
	public void setLocked(boolean isLocked) {
		getAuditBlock().setLocked(isLocked);
	}

	@Override
	public boolean isLocked() {
		return getAuditBlock().isLocked();
	}
	
	@Override
	public FmmLockStatus getLockStatus() {
		return getAuditBlock().getLockStatus();
	}

	////  END Audit Block Wrapper ////

	@Override
	public void onFlingUp() {
		this.getActiveDocumentSectionView().onFlingUp();
	}

	@Override
	public void onFlingDown() {
		this.getActiveDocumentSectionView().onFlingDown();
	}

	@Override
	public void onFlingRight() {
		this.getActiveDocumentSectionView().onFlingRight();
	}

	@Override
	public void onFlingLeft() {
		this.getActiveDocumentSectionView().onFlingLeft();
	}

	@Override
	public float getPreviousMotionEventX() {
		return this.previousMotionEventX;
	}

	@Override
	public float getPreviousMotionEventY() {
		return this.previousMotionEventY;
	}

	@Override
	public void setPreviousMotionEventX(float aMotionEventX) {
		this.previousMotionEventX = aMotionEventX;
	}

	@Override
	public void setPreviousMotionEventY(float aMotionEventY) {
		this.previousMotionEventY = aMotionEventY;
	}
	
	///////  end Fling  /////////

	public void postPersistenceProcessing() {
		setAsNewBaseline();
		this.historySectionView.refresh();
	}

	public void setAsNewBaseline() {
		this.baselineDocument = new FseDocument(getJsonObject().toString());
		this.storySectionView.setAsNewBaseline();
		this.notesSectionView.setAsNewBaseline();
		resetModificationState();
	}

	private void resetModificationState() {
		this.storySectionView.resetModificationState();
		this.notesSectionView.resetModificationState();
	}

	public void updateHistory(Date aTimestamp, FseDocumentTransactionType aDocumentTransactionType) {
		FseDocumentSectionParagraphAudit theStoryAudit = this.storySectionView.getParagraphAudit();
		FseDocumentSectionParagraphAudit theNotesAudit = this.notesSectionView.getParagraphAudit();
		getHistorySectionView().updateHistory(aTimestamp, aDocumentTransactionType, theStoryAudit, theNotesAudit, this.baselineDocument);
	}

	public FseContentModificationState getModificationState() {
		if(getStorySectionView().getContentModificationState() == FseContentModificationState.NEW) {
			return FseContentModificationState.NEW;
		}
		if(getStorySectionView().getModificationState() != FseContentModificationState.UNCHANGED || getNotesSectionView().getModificationState() != FseContentModificationState.UNCHANGED) {
			return FseContentModificationState.MODIFIED;
		}
		/*
		 *  TODO - someday will have to check other document sections, such as
		 *  a change to the history compression parameret in History
		 */
		return FseContentModificationState.UNCHANGED;
	}

	public void updateAuditBlock(Date aTimestamp, FseDocumentTransactionType aDocumentTransactionType) {
		getAuditSectionView().update(aTimestamp, aDocumentTransactionType);
		
	}

	public void saveDocument() {
		this.fseFragment.saveDocument();
	}

	public void newDocument() {
		this.fseFragment.newDocument();
	}

}
